package com.portalito.jahepi.modelo;

import java.util.ArrayList;
import java.util.Iterator;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;

import com.portalito.jahepi.Utils;
import com.portalito.jahepi.dto.Almacen;
import com.portalito.jahepi.dto.Cliente;
import com.portalito.jahepi.dto.PedidoVenta;
import com.portalito.jahepi.dto.Producto;
import com.portalito.jahepi.dto.Ticket;
import com.portalito.jahepi.dto.Unidad;
import com.portalito.jahepi.dto.Usuario;


/* Data Access Object */

public class DAO {
	
	private final static String TAG = "DAO";
	private DB db;
	
	public DAO(Context context) {
		db = new DB(context);
		Log.d(TAG, "DAO inicializado");
	}
	
	public Usuario obtenerUsuario(String usuario, String clave) {
		Cursor cursor = db.obtener("usuarios", String.format("usuario='%s' AND clave = '%s' AND activo = 1", usuario, clave));
		if(cursor != null) {
			Usuario usuarioDto = new Usuario();
			usuarioDto.setUsuario(cursor.getString(0));
			usuarioDto.setClave(cursor.getString(1));
			usuarioDto.setNombre(cursor.getString(2) != null ? cursor.getString(2) : "");
			usuarioDto.setFechaModificacion(cursor.getString(3));
			usuarioDto.setActivo(cursor.getInt(4) != 0);
			usuarioDto.setPermisoPedidoVenta(cursor.getInt(5) != 0);
			usuarioDto.setPermisoTicket(cursor.getInt(6) != 0);
			cursor.close();
			
			ArrayList<Unidad> unidades = obtenerUnidadesPorUsuario(usuario);
			Iterator<Unidad> iterator = unidades.iterator();
			while(iterator.hasNext()) {
				usuarioDto.agregarUnidad(iterator.next());
			}
			
			return usuarioDto;
		}
		return null;
	}
	
	public Usuario obtenerUsuario(String usuario) {
		Cursor cursor = db.obtener("usuarios", String.format("usuario='%s'", usuario));
		if(cursor != null) {
			Usuario usuarioDto = new Usuario();
			usuarioDto.setUsuario(cursor.getString(0));
			usuarioDto.setClave(cursor.getString(1));
			usuarioDto.setNombre(cursor.getString(2));
			usuarioDto.setFechaModificacion(cursor.getString(3));
			usuarioDto.setActivo(cursor.getInt(4) != 0);
			usuarioDto.setPermisoPedidoVenta(cursor.getInt(5) != 0);
			usuarioDto.setPermisoTicket(cursor.getInt(6) != 0);
			cursor.close();
			return usuarioDto;
		}
		return null;
	}
	
	public Producto obtenerProducto(String id) {
		Cursor cursor = db.obtener("productos", String.format("id='%s'", id));
		if(cursor != null) {
			Producto productoDto = new Producto(cursor.getString(0), cursor.getString(1), cursor.getString(2));
			productoDto.setFechaModificacion(cursor.getString(3));
			productoDto.setActivo(cursor.getInt(4) != 0);
			cursor.close();
			return productoDto;
		}
		return null;
	}
	
	public ArrayList<Producto> obtenerProductos() {
		ArrayList<Producto> productos = new ArrayList<Producto>();
		Cursor cursor = db.obtenerTodos("productos", null);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Producto productoDto = new Producto(cursor.getString(0), cursor.getString(1), cursor.getString(2));
				productoDto.setFechaModificacion(cursor.getString(3));
				productoDto.setActivo(cursor.getInt(4) != 0);
				productos.add(productoDto);
			}
			cursor.close();
		}
		return productos;
	}
	
	public ArrayList<Producto> obtenerProductosPorCriterio(String criterio) {
		ArrayList<Producto> productos = new ArrayList<Producto>();
		Cursor cursor = db.obtenerTodos("productos", "id LIKE '%" + criterio + "%' OR descripcion LIKE  '%" + criterio + "%'");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Producto productoDto = new Producto(cursor.getString(0), cursor.getString(1), cursor.getString(2));
				productoDto.setFechaModificacion(cursor.getString(3));
				productoDto.setActivo(cursor.getInt(4) != 0);
				productos.add(productoDto);
			}
			cursor.close();
		}
		return productos;
	}
	
	public ArrayList<Unidad> obtenerUnidades() {
		ArrayList<Unidad> unidades = new ArrayList<Unidad>();
		Cursor cursor = db.obtenerTodos("unidades", null);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Unidad unidadDto = new Unidad(cursor.getString(0), cursor.getString(1));
				unidadDto.setFechaModificacion(cursor.getString(2));
				unidades.add(unidadDto);
			}
			cursor.close();
		}
		return unidades;
	}
	
	public Unidad obtenerUnidad(String id) {
		Cursor cursor = db.obtener("unidades", String.format("id='%s'", id));
		if(cursor != null) {
			Unidad unidadDto = new Unidad(cursor.getString(0), cursor.getString(1));
			unidadDto.setFechaModificacion(cursor.getString(2));
			cursor.close();
			return unidadDto;
		}
		return null;
	}
	
	public ArrayList<Unidad> obtenerUnidadesPorUsuario(String usuario) {
		ArrayList<Unidad> unidades = new ArrayList<Unidad>();
		Cursor cursor = db.obtenerUnidadesPorUsuario(usuario);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Unidad unidadDto = new Unidad(cursor.getString(0), cursor.getString(1));
				unidadDto.setFechaModificacion(cursor.getString(2));
				unidades.add(unidadDto);
			}
			cursor.close();
		}
		return unidades;
	}
	
	public Almacen obtenerAlmacen(String id) {
		Cursor cursor = db.obtener("almacenes", String.format("id='%s'", id));
		if(cursor != null) {
			Almacen almacenDto = new Almacen(cursor.getString(0), cursor.getString(1), obtenerUnidad(cursor.getString(3)));
			almacenDto.setFechaModificacion(cursor.getString(2));
			cursor.close();
			return almacenDto;
		}
		return null;
	}
	
	public ArrayList<Almacen> obtenerAlmacenesPorUnidad(String unidad) {
		ArrayList<Almacen> almacenes = new ArrayList<Almacen>();
		Cursor cursor = db.obtenerTodos("almacenes", String.format("unidad='%s'", unidad));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Almacen almacenDto = new Almacen(cursor.getString(0), cursor.getString(1), obtenerUnidad(cursor.getString(3)));
				almacenDto.setFechaModificacion(cursor.getString(2));
				almacenes.add(almacenDto);
			}
			cursor.close();
		}
		return almacenes;
	}
	
	public Cliente obtenerCliente(String id) {
		Cursor cursor = db.obtener("clientes", String.format("id='%s'", id));
		if(cursor != null) {
			Cliente clienteDto = new Cliente(cursor.getString(0), cursor.getString(1));
			clienteDto.setFechaModificacion(cursor.getString(2));
			cursor.close();
			return clienteDto;
		}
		return null;
	}
	
	public ArrayList<Cliente> obtenerClientes() {
		ArrayList<Cliente> clientes = new ArrayList<Cliente>();
		Cursor cursor = db.obtenerTodos("clientes", null);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Cliente clienteDto = new Cliente(cursor.getString(0), cursor.getString(1));
				clienteDto.setFechaModificacion(cursor.getString(2));
				clientes.add(clienteDto);
			}
			cursor.close();
		}
		return clientes;
	}
	
	public ArrayList<Cliente> obtenerClientesPorCriterio(String criterio) {
		ArrayList<Cliente> clientes = new ArrayList<Cliente>();
		Cursor cursor = db.obtenerTodos("clientes", "id LIKE '%" + criterio + "%' OR nombre LIKE  '%" + criterio + "%'");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Cliente clienteDto = new Cliente(cursor.getString(0), cursor.getString(1));
				clienteDto.setFechaModificacion(cursor.getString(2));
				clientes.add(clienteDto);
			}
			cursor.close();
		}
		return clientes;
	}
	
	public ArrayList<Ticket> obtenerTicketsNoSincronizados() {
		ArrayList<Ticket> tickets = new ArrayList<Ticket>();
		Cursor cursor = db.obtenerTodos("tickets", "sincronizado IS NULL");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Ticket ticketDto = new Ticket(
					cursor.getInt(0),
					obtenerUsuario(cursor.getString(1)),
					cursor.getDouble(2),
					cursor.getDouble(3),
					cursor.getString(4),
					cursor.getInt(5),
					cursor.getInt(6),
					cursor.getInt(7),
					cursor.getString(8)
				);
				tickets.add(ticketDto);
			}
			cursor.close();
		}
		return tickets;
	}
	
	public ArrayList<PedidoVenta> obtenerPedidosVentaNoSincronizados() {
		ArrayList<PedidoVenta> pedidos = new ArrayList<PedidoVenta>();
		Cursor cursor = db.obtenerTodos("pedidos", "sincronizado IS NULL");
		if(cursor != null) {
			while(cursor.moveToNext()) {
				PedidoVenta pedidoDto = new PedidoVenta(
					cursor.getInt(0),
					obtenerUsuario(cursor.getString(1)),
					obtenerUnidad(cursor.getString(10)),
					obtenerAlmacen(cursor.getString(11)),
					obtenerCliente(cursor.getString(12)),
					obtenerProducto(cursor.getString(5)),
					cursor.getDouble(8),
					cursor.getDouble(7),
					cursor.getDouble(2),
					cursor.getDouble(3),
					cursor.getString(4),
					cursor.getString(9)
				);
				pedidos.add(pedidoDto);
			}
			cursor.close();
		}
		return pedidos;
	}
	
	public boolean guardarUsuario(Usuario usuario) {
		if(usuario != null) {
			ContentValues values = new ContentValues();
			values.put("clave", usuario.getClave());
			values.put("nombre", usuario.getNombre());
			values.put("activo", usuario.estaActivo() ? 1 : 0);
			values.put("permiso_pedido_venta", usuario.tienePermisoPedidoVenta() ? 1 : 0);
			values.put("permiso_ticket", usuario.tienePermisoTicket() ? 1 : 0);
			values.put("fecha_modificacion", usuario.getFechaModificacionString());
			
			Usuario usuarioDB = obtenerUsuario(usuario.getUsuario());
			if(usuarioDB != null) {
				if(usuarioDB.esMayorFechaModificacion(usuario)) {
					db.actualizar("usuarios", values, String.format("usuario='%s'", usuario.getUsuario()));
				}
			} else {
				values.put("usuario", usuario.getUsuario());
				db.insertar("usuarios", values);
			}
			
			if(usuario.tieneUnidades()) {
				String[] unidadesIds = new String[usuario.getCantidadUnidades()];
				int i = 0;
				Iterator<Unidad> iterator = usuario.obtenerUnidadesIterator();
				while(iterator.hasNext()) {
					Unidad unidad = iterator.next();
					ContentValues values2 = new ContentValues();
					values2.put("usuario", usuario.getUsuario());
					values2.put("unidad", unidad.getId());
					unidadesIds[i] = "'" + unidad.getId() + "'";
					db.insertar("unidades_usuarios", values2);
					i++;
				}
				db.borrarUnidadesUsuarioExcepto(unidadesIds, usuario.getUsuario());
			} else {
				db.borrar("unidades_usuarios", String.format("usuario='%s'", usuario.getUsuario()));
			}
			return true;
		}
		return false;
	}
	
	public boolean guardarAlmacen(Almacen almacen) {
		if(almacen != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", almacen.getNombre());
			values.put("unidad", almacen.getUnidadId());
			values.put("fecha_modificacion", almacen.getFechaModificacionString());
			
			Almacen almacenDB = obtenerAlmacen(almacen.getId());
			if(almacenDB != null) {
				if(almacenDB.esMayorFechaModificacion(almacen)) {
					return db.actualizar("almacenes", values, String.format("id='%s'", almacen.getId()));
				}
			} else {
				values.put("id", almacen.getId());
				return db.insertar("almacenes", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean guardarUnidad(Unidad unidad) {
		if(unidad != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", unidad.getNombre());
			values.put("fecha_modificacion", unidad.getFechaModificacionString());
			
			Unidad unidadDB = obtenerUnidad(unidad.getId());
			if(unidadDB != null) {
				if(unidadDB.esMayorFechaModificacion(unidad)) {
					return db.actualizar("unidades", values, String.format("id='%s'", unidad.getId()));
				}
			} else {
				values.put("id", unidad.getId());
				return db.insertar("unidades", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean guardarCliente(Cliente cliente) {
		if(cliente != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", cliente.getNombre());
			values.put("fecha_modificacion", cliente.getFechaModificacionString());
			
			Cliente clienteDB = obtenerCliente(cliente.getId());
			if(clienteDB != null) {
				if(clienteDB.esMayorFechaModificacion(cliente)) {
					return db.actualizar("clientes", values, String.format("id='%s'", cliente.getId()));
				}
			} else {
				values.put("id", cliente.getId());
				return db.insertar("clientes", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean guardarProducto(Producto producto) {
		if(producto != null) {
			ContentValues values = new ContentValues();
			values.put("descripcion", producto.getDescripcion());
			values.put("unidad", producto.getUnidad());
			values.put("fecha_modificacion", producto.getFechaModificacionString());
			values.put("activo", producto.estaActivo() ? 1 : 0);
			
			Producto productoDB = obtenerProducto(producto.getId());
			if(productoDB != null) {
				if(productoDB.esMayorFechaModificacion(producto)) {
					return db.actualizar("productos", values, String.format("id='%s'", producto.getId()));
				}
			} else {
				values.put("id", producto.getId());
				return db.insertar("productos", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean guardarPedidoVenta(PedidoVenta pedido) {
		if(pedido != null) {
			ContentValues values = new ContentValues();
			values.put("producto", pedido.getProductoId());
			values.put("cliente", pedido.getClienteId());
			values.put("precio", pedido.getPrecio());
			values.put("cantidad", pedido.getCantidad());
			values.put("latitud", pedido.getLatitud());
			values.put("longitud", pedido.getLongitud());
			values.put("dispositivo", pedido.getDispositivo());
			values.put("fecha", pedido.getFecha());
			values.put("usuario", pedido.getUsuarioId());
			values.put("almacen", pedido.getAlmacenId());
			values.put("unidad", pedido.getUnidadId());
			long id = db.insertar("pedidos", values);
			if(id != DB.ERROR) {
				pedido.setId((int)id);
				return true;
			}
			return false;
		} 
		return false;
	}
	
	public boolean guardarTicket(Ticket ticket) {
		if(ticket != null) {
			ContentValues values = new ContentValues();
			values.put("usuario", ticket.getUsuarioId());
			values.put("latitud", ticket.getLatitud());
			values.put("longitud", ticket.getLongitud());
			values.put("fecha", ticket.getFecha());
			values.put("transno", ticket.getTransno());
			values.put("tipo", ticket.getTipo());
			values.put("orden", ticket.getOrden());
			values.put("dispositivo", ticket.getDispositivo());
			
			long result = db.insertar("tickets", values);
			return result != DB.ERROR;
		}
		return false;
	}
	
	public boolean actualizarTicketComoSincronizado(Ticket ticket) {
		if(ticket != null) {
			ContentValues values = new ContentValues();
			values.put("sincronizado", 1);
			return db.actualizar("tickets", values, String.format("id='%s'", ticket.getId()));
		}
		return false;
	}
	
	public boolean actualizarPedidoVentaComoSincronizado(PedidoVenta pedido) {
		if(pedido != null) {
			ContentValues values = new ContentValues();
			values.put("sincronizado", 1);
			return db.actualizar("pedidos", values, String.format("id='%s'", pedido.getId()));
		}
		return false;
	}
	
	public void borrarProductosExcepto(ArrayList<Producto> productos) {
		int size = productos.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Producto> iterator = productos.iterator();
			while(iterator.hasNext()) {
				Producto producto = iterator.next();
				condiciones[i] = String.format("'%s'", producto.getId()); i++;
			}
			db.borrar("productos", "NOT IN (" + Utils.implode(condiciones, ",") + ")");
		} else {
			db.borrar("productos", null);
		}
	}
	
	public void borrarAlmacenesExcepto(ArrayList<Almacen> almacenes) {
		int size = almacenes.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Almacen> iterator = almacenes.iterator();
			while(iterator.hasNext()) {
				Almacen almacen = iterator.next();
				condiciones[i] = String.format("'%s'", almacen.getId()); i++;
			}
			db.borrar("almacenes", "NOT IN (" + Utils.implode(condiciones, ",") + ")");
		} else {
			db.borrar("almacenes", null);
		}
	}
	
	public void borrarClientesExcepto(ArrayList<Cliente> clientes) {
		int size = clientes.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<Cliente> iterator = clientes.iterator();
			while(iterator.hasNext()) {
				Cliente cliente = iterator.next();
				condiciones[i] = String.format("'%s'", cliente.getId()); i++;
			}
			db.borrar("clientes", "NOT IN (" + Utils.implode(condiciones, ",") + ")");
		} else {
			db.borrar("clientes", null);
		}
	}
}
